package com.leadiv.cards;

import com.leadiv.cards.Rook.RookCard;
import com.leadiv.cards.Rook.RookPlayer;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author pborrego
 */
public class Round {
    private Vector<RookPlayer> players;
    private int leadPlayerIndex;
    private Vector<Trick> tricks;
    private Bidding bids;
    private int maxBid = 120;
    private int minBid = 70;
    private Vector<RookCard> nest;
    private String trump;
    private int trickCount;

    private Vector<Integer> points;
    private int nestPoints;
    private final int playersCount;
    private final int nestSize;
    private int lastPlayerIndex;
    private Deck<RookCard> deck;

    public Round(Deck<RookCard> deck, int nestSize, Vector<RookPlayer> players, int dealer)
    {
        int firstBidder;
        this.players = players;
        this.nest = new Vector<RookCard>();
        this.points = new Vector<Integer>();
        this.playersCount = this.players.size();
        this.lastPlayerIndex = -1;
        this.leadPlayerIndex = -1;
        this.trump = "";
        this.tricks = new Vector<Trick>();

        firstBidder = (dealer + 1) % this.playersCount;
        this.bids = new Bidding(this.maxBid, this.minBid, this.playersCount, firstBidder);

        this.deck = deck;
        this.nestSize = nestSize;

        for(int i=0; i<this.playersCount; i++)
            this.points.add(new Integer(0));
    }

    public int nestPoints()
    {
        Iterator<RookCard> iter = this.nest.iterator();
        RookCard c;
        int pts = 0;
        while(iter.hasNext())
        {
            c = iter.next();
            pts += c.getValue();
        }

        return pts;
    }

    private void calculatePoints()
    {
        Iterator<Trick> iter = this.tricks.iterator();
        Trick t;
        int pointIndex, prevPts;

        pointIndex = -1;
        while(iter.hasNext())
        {
            t = iter.next();
            pointIndex = (t.getLed() + t.getWinnerIndexOffset()) % this.playersCount;
            prevPts = this.points.get(pointIndex).intValue();
            this.points.set(pointIndex, new Integer(t.getPoints() + prevPts));
        }

        this.lastPlayerIndex = pointIndex;
        this.nestPoints = this.nestPoints();
    }

    public int getTeamScore(Vector<Integer> teamIndexes)
    {
        Iterator<Integer> iter = teamIndexes.iterator();
        int playerIndex;
        int teamScore = 0;

        while(iter.hasNext())
        {
            playerIndex = iter.next().intValue();
            teamScore += this.getScore(playerIndex);

            if(playerIndex == this.lastPlayerIndex)
                teamScore += this.nestPoints;
        }

        return teamScore;
    }

    private int getScore(int playerIndex)
    {
        return this.points.get(playerIndex).intValue();
    }

    public void deal()
    {
        int i = 0;
        RookCard c[][] = new RookCard[this.playersCount + 1][];

        int handSize = (int)((this.deck.deckCount() - this.nestSize) / this.playersCount);
        for(i=1; i<=this.playersCount; i++)
        {
            try { c[i] = new RookCard[handSize]; } catch (java.lang.NegativeArraySizeException nase) { System.out.println(i); nase.printStackTrace(); System.exit(1); }
        }

        c[0] = new RookCard[this.nestSize];

        try {
            this.deck.dealPlayers(this.playersCount + 1, c);
        } catch (EmptyDeckException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }

        for(i=1; i<=this.playersCount; i++)
        {
            this.players.get(i - 1).newHand(c[i]);
        }

        this.nest.addAll(Arrays.asList(c[0]));

        this.trickCount = handSize;
    }

    public RookPlayer bid()
    {
        RookPlayer cp;

        while(!bids.doneBidding())
        {
            try {
                cp = this.bids.getCurrentBidder(this.players);
                this.bids.bid(cp.bid());
            } catch (InvalidBidException ex) {
                Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        this.leadPlayerIndex = (this.bids.getWinnerIndex() + 1) % this.players.size();
        return this.bids.getWinner(this.players);
    }

    public Vector<RookCard> getNest() {
        return nest;
    }

    public String getTrump() {
        return trump;
    }
    
    public void declareTrump(RookPlayer winner)
    {
        this.trump = winner.chooseTrump(this.nest);
    }

    public void playTrick()
    {
        Trick t = new Trick(this.leadPlayerIndex, this.trump);
        int i = 0;
        final int playerSize = this.players.size();
        RookPlayer p;

        for(; i<playerSize; i++)
        {
            p = this.players.get((this.leadPlayerIndex + i) % playerSize);
            p.play(t);
        }

        // Set the next person to lead.
        this.leadPlayerIndex = (this.leadPlayerIndex + t.getWinnerIndexOffset()) % playerSize;

        // add the trick to the tricks history
        this.tricks.add(t);

        this.trickCount--;

        if(!this.hasMoreTricks())
            this.calculatePoints();
    }

    public boolean hasMoreTricks()
    {
        return this.trickCount > 0;
    }

    public void printRound()
    {
        Iterator<RookCard> iterCards;
        Iterator<RookPlayer> iterPlayers;
        Iterator<Trick> iterTricks;
        RookCard c;
        RookPlayer p;
        String output = "";
        int cnt = 0;
        RookPlayer winner = null;

        if(this.bids.doneBidding())
        {
            winner = this.bids.getWinner(this.players);
        }

        System.out.println("=======================");
        System.out.println("=  ROUND INFORMATION  =");
        System.out.println("=======================");
        // Print the Nest
        System.out.println("========= Nest ========");
        iterCards = this.nest.iterator();
        while(iterCards.hasNext())
        {
            c = iterCards.next();
            output += c.getSuit() + " " + c.getFace() + ", ";
        }
        output += ";";
        output = output.replace(", ;", "");
        System.out.println(output);

        // Print out the Player's hands
        System.out.println("\n==== Player's Hands ===");
        iterPlayers = this.players.iterator();
        while(iterPlayers.hasNext())
        {
            p = iterPlayers.next();

            if(p.equals(winner))
            {
                System.out.print("*");
            }

            System.out.print("Player " + cnt + ": ");
            p.showHand();
            cnt++;
        }

        // Print out the current bid information
        System.out.println("\n=== Bid Information ===");
        this.bids.printBidInfo();

        // Print out the declared trump
        System.out.println("\n======== Trump ========");
        System.out.println(this.trump);

        // Print out he history of the tricks
        System.out.println("\n==== Trick History ====");
        iterTricks = this.tricks.iterator();
        while(iterTricks.hasNext())
        {
            iterTricks.next().printTrick();
        }

        System.out.println("\n\n");
    }
}
